// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module MF101_A01
(
    // global signals
    input  wire         I_osc_25M, // 25M

    // video input
    input  wire         I_vin_pclk,
    input  wire         I_vin_vsync,
    input  wire         I_vin_de,
    input  wire [23: 0] I_vin_data,

    // RGMII
    output wire         phy0_rst_n,
    output wire         phy1_rst_n,

    output wire         mdc,
    output wire         mdio,

    output wire         rgmii_p0_txc,
    output wire         rgmii_p0_txen,
    output wire [ 3: 0] rgmii_p0_txd,
    output wire         rgmii_p1_txc,
    output wire         rgmii_p1_txen,
    output wire [ 3: 0] rgmii_p1_txd,

    input  wire         rgmii_p0_rxc,
    input  wire         rgmii_p0_rxdv,
    input  wire [ 3: 0] rgmii_p0_rxd,
    input  wire         rgmii_p1_rxc,
    input  wire         rgmii_p1_rxdv,
    input  wire [ 3: 0] rgmii_p1_rxd,

    // audio
    // output wire         mclk,
    // input  wire         lrck,
    // input  wire         sck,
    // input  wire         sda,

    // LEDs
    // output wire         p0_led,
    // output wire         p1_led,
    output reg          O_led0,

    // sdm - internal sdram
    inout  wire [31:0]  sdm_data,
    output wire [10:0]  sdm_addr,
    output wire [3:0]   sdm_dqm,
    output wire [1:0]   sdm_bank,
    output wire         sdm_cas,
    output wire         sdm_ras,
    output wire         sdm_we,
    output wire         sdm_clk,
    output wire         sdm_cs,
    output wire         sdm_cke,

    // spi interface
    input  wire         mcu_clk,
    input  wire         mcu_cs,
    input  wire         mcu_dat_in,
    output wire         mcu_dat_out,
	
    input  wire         flash_SO,
    input  wire         flash_SCK,
    input  wire         flash_SI,
    input  wire         flash_CS_n

);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam [31:0]
    DATE           = 32'h19_10_28_10;

localparam // sdm_arbi_state
    SDM_ARBI_IDLE = 0,
    SDM_ARBI_VIB_1 = 1,
    SDM_ARBI_VIB_2 = 1<<1,
    SDM_ARBI_P0 = 1<<2,
    SDM_ARBI_P1 = 1<<3,
    SDM_ARBI_P2 = 1<<4,
    SDM_ARBI_P3 = 1<<5;

localparam [ 7: 0] 
    MAIN_FUNCTION  = "M",
    SUB_FUNCTION   = "F",
    MAIN_SOLUTION  = 8'd1,
    SUB_SOLUTION   = 8'h01,
    APP_TYPE       = "A",
    MAIN_VERSION   = 8'h01,
    SUB_VERSION    = 8'd0,
    MINI_VERSION   = 8'd0;

localparam
    MAX_VIN_WIDTH = 4094;

localparam
    FRAME1_START_ADDR = 512 * 1024 * 4 / 2;

localparam
    START_IDLE = 2'b00,
    START_DELAY = 2'b01,
    START_OK = 2'b10;

/******************************************************************************
                              <internal signals>
******************************************************************************/
// clocks
wire         sclk;
wire         vin_pclk;
// resets
wire         init_pll;
reg  [ 5: 0] reset_init = 6'b0 /* synthesis syn_preserve = 1*/;
wire         rst_n;
reg          phy_rst_n;
// vib_top
wire         new_frame;
wire         vib_use_buf1;
reg          send_disp_set_pkg_start;
reg  [ 5: 0] sdm_arbi_state;
reg  [ 5: 0] next_sdm_arbi_state;

//--------------------------------------------------------------------
// memory
//--------------------------------------------------------------------
// req & ack
wire          sdm1_vib_req;
reg           sdm1_vib_ack;
wire          sdm2_vib_req;
reg           sdm2_vib_ack;
wire          sdm_vob_req_p0;
reg           sdm_vob_ack_p0;
wire          sdm_vob_req_p1;
reg           sdm_vob_ack_p1;
wire          sdm_vob_req_p2;
reg           sdm_vob_ack_p2;
wire          sdm_vob_req_p3;
reg           sdm_vob_ack_p3;
// vib
wire          sdm1_sdram_wr_en;
wire [ 31: 0] sdm1_sdram_start_addr;
wire [ 15: 0] sdm1_sdram_length;
wire          sdm1_sdram_ask_for_data;
wire [ 31: 0] sdm1_sdram_wdata;
wire          sdm2_sdram_wr_en;
wire [ 31: 0] sdm2_sdram_start_addr;
wire [ 15: 0] sdm2_sdram_length;
wire          sdm2_sdram_ask_for_data;
wire [ 31: 0] sdm2_sdram_wdata;
// p0
wire          sdm_sdram_rd_en_p0;
wire [ 31: 0] sdm_sdram_start_addr_p0;
wire [ 15: 0] sdm_sdram_length_p0;
// p1
wire          sdm_sdram_rd_en_p1;
wire [ 31: 0] sdm_sdram_start_addr_p1;
wire [ 15: 0] sdm_sdram_length_p1;
// p2
wire          sdm_sdram_rd_en_p2;
wire [ 31: 0] sdm_sdram_start_addr_p2;
wire [ 15: 0] sdm_sdram_length_p2;
// p3
wire          sdm_sdram_rd_en_p3;
wire [ 31: 0] sdm_sdram_start_addr_p3;
wire [ 15: 0] sdm_sdram_length_p3;
// sdram_ctrl
wire          sdm_sdram_wr_rd_end;
wire          sdm_sdram_wr_en;
wire          sdm_sdram_rd_en;
wire [ 31: 0] sdm_sdram_start_addr;
wire [ 15: 0] sdm_sdram_length;
wire          sdm_sdram_ask_for_data;
wire [ 31: 0] sdm_sdram_wdata;
wire [ 31: 0] sdm_sdram_rdata;
wire          sdm_sdram_rdata_valid;

// phy check
reg  [16:0]  ms_cnt;
reg          ms_tick;
reg  [1:0]   start_state;
reg  [1:0]   next_start_state;
reg  [7:0]   delay_cnt;
wire         p0_rxc;
wire         p0_rxdv;
wire         p0_rxer;
wire         p1_rxc;
wire         p1_rxdv;
wire         p1_rxer;
wire         p0_error;
wire         p1_error;
wire         p0_in_1000M;
wire         p1_in_1000M;
reg  [3:0]   reset_phy_sync;
reg          check_phy;
reg  [13:0]  check_phy_timer;

// audio
wire audio_data_valid;
wire [ 7: 0] audio_data;

// reboot to test
wire reboot_to_test_p0;
wire reboot_to_test_p1;
reg  reboot_to_test;
reg  [ 2: 0] reboot_to_test_cnt;
reg  reg_rb_need_reboot_to_test;

//--------------------------------------------------------------------
// registers
//--------------------------------------------------------------------
wire          action_wren;
wire          cfg_wren;
wire          extra_cfg_wren;
wire [  3: 0] px_pkg_ram_wren;
wire [ 11: 0] waddr;
wire [  7: 0] wdata;
wire [ 11: 0] raddr;
wire          status_rden;
wire [  7: 0] status_rdata;
wire          action_rden;
wire [  7: 0] action_rdata;
wire          cfg_rden;
wire [  7: 0] cfg_rdata;
wire          extra_rden;
wire [  7: 0] extra_rdata;

wire [  3: 0] px_pkg_ram_rden;
wire [  7: 0] p0_pkg_ram_rdata;
wire [  7: 0] p1_pkg_ram_rdata;
wire [  3: 0] px_comm_back_ram_rden;
wire [  7: 0] p0_comm_back_ram_rdata;
wire [  7: 0] p1_comm_back_ram_rdata;

//--------------------------------------------------------------------
// common
wire          reg_vib_enable;
wire [  7: 0] reg_nop_bytes;
wire [  8: 0] reg_frame_pkg_byte_num;
wire [ 10: 0] reg_disp_set_pkg_byte_num;
wire [ 11: 0] reg_idle_pkg_byte_num;
wire [ 11: 0] reg_comm_pkg_byte_num;
wire [ 11: 0] reg_rb_vin_width;
wire [ 10: 0] reg_rb_vin_height;
wire [ 11: 0] reg_rb_vin_width_to_pc;
wire [ 10: 0] reg_rb_vin_height_to_pc;
wire [  7: 0] reg_rb_vin_frame_rate;
//wire          reg_rb_ddr3_err;
wire [ 23: 0] reg_reboot_addr;
wire          reg_reboot_en;
wire          reg_reset_ddr3;
wire          reg_rb_video_not_active;
wire          reg_px_send_comm_pkg;
wire          reg_px_enable;
wire [ 11: 0] reg_px_start_row_offset;
wire [ 11: 0] reg_px_start_col_offset;
wire [ 11: 0] reg_vin_max_width;
wire [ 11: 0] reg_vin_max_height;
wire          reg_mac_addr_incr_en;
wire [ 11: 0] reg_max_pixel_num_in_one_trans;
wire          reg_long_pkg_en;
// p0
wire          reg_p0_enable;
wire [ 10: 0] reg_p0_start_row;
wire [ 11: 0] reg_p0_start_col;
wire [ 11: 0] reg_p0_width;
wire [ 10: 0] reg_p0_height;
wire          reg_p0_disable_disp_set_pkg;
wire          reg_p0_audio_enable;
wire [ 11: 0] reg_p0_line_step;
wire          reg_p0_send_comm_pkg;
wire          reg_p0_rb_comm_back_flag;
wire          reg_p0_rb_comm_back_crc_err;
wire [ 11: 0] reg_p0_rb_comm_back_length;
wire          reg_p0_clr_comm_back_flag;
wire          reg_p0_rb_sending_comm_pkg;
// p1
wire          reg_p1_enable;
wire [ 10: 0] reg_p1_start_row;
wire [ 11: 0] reg_p1_start_col;
wire [ 11: 0] reg_p1_width;
wire [ 10: 0] reg_p1_height;
wire          reg_p1_disable_disp_set_pkg;
wire          reg_p1_audio_enable;
wire [ 11: 0] reg_p1_line_step;
wire          reg_p1_send_comm_pkg;
wire          reg_p1_rb_comm_back_flag;
wire          reg_p1_rb_comm_back_crc_err;
wire [ 11: 0] reg_p1_rb_comm_back_length;
wire          reg_p1_clr_comm_back_flag;
wire          reg_p1_rb_sending_comm_pkg;
//
wire [ 11: 0] reg_upscale_width;
wire          reg_is_sv5;
wire [ 11: 0] reg_screen_v;
wire [  7: 0] reg_vin_mode;

wire [ 7: 0]  reg_Android_state;

/******************************************************************************
                                <module body>
******************************************************************************/
//--------------------------------------------------------------------
// register access
//--------------------------------------------------------------------
spi_top u_spi_top
(
    .I_sclk(sclk),
    .I_rst_n(rst_n),
    .I_mcu_clk(mcu_clk),
    .I_mcu_cs(mcu_cs),
    .I_mcu_dat_in(mcu_dat_in),
    .O_mcu_dat_out(mcu_dat_out),
    .O_action_wren(action_wren),
    .O_cfg_wren(cfg_wren),
    .O_extra_cfg_wren(extra_cfg_wren),
    .O_px_pkg_ram_wren(px_pkg_ram_wren),
    .O_waddr(waddr),
    .O_wdata(wdata),
    .O_raddr(raddr),
    .O_status_rden(status_rden),
    .I_status_rdata(status_rdata),
    .O_action_rden(action_rden),
    .I_action_rdata(action_rdata),
    .O_cfg_rden(cfg_rden),
    .I_cfg_rdata(cfg_rdata),
    .O_extra_rden(extra_rden),
    .I_extra_rdata(extra_rdata),
    .O_px_pkg_ram_rden(px_pkg_ram_rden),
    .I_p0_pkg_ram_rdata(p0_pkg_ram_rdata),
    .I_p1_pkg_ram_rdata(p1_pkg_ram_rdata),
    .I_p2_pkg_ram_rdata(),
    .I_p3_pkg_ram_rdata(),
    .O_px_comm_back_ram_rden(px_comm_back_ram_rden),
    .I_p0_comm_back_ram_rdata(p0_comm_back_ram_rdata),
    .I_p1_comm_back_ram_rdata(p1_comm_back_ram_rdata),
    .I_p2_comm_back_ram_rdata(),
    .I_p3_comm_back_ram_rdata()
);

regfile u_regfile
(
    .I_sclk(sclk),
    .I_rst_n(rst_n),
    .I_action_wren(action_wren),
    .I_cfg_wren(cfg_wren),
    .I_extra_cfg_wren(extra_cfg_wren),
    .I_waddr(waddr),
    .I_wdata(wdata),
    .I_raddr(raddr),
    .I_status_rden(status_rden),
    .O_status_rdata(status_rdata),
    .I_action_rden(action_rden),
    .O_action_rdata(action_rdata),
    .I_cfg_rden(cfg_rden),
    .O_cfg_rdata(cfg_rdata),
    .I_extra_rden(extra_rden),
    .O_extra_rdata(extra_rdata),
    .I_reg_rb_main_function(MAIN_FUNCTION),
    .I_reg_rb_sub_function(SUB_FUNCTION),
    .I_reg_rb_main_solution(MAIN_SOLUTION),
    .I_reg_rb_sub_solution(SUB_SOLUTION),
    .I_reg_rb_app_type(APP_TYPE),
    .I_reg_rb_main_version(MAIN_VERSION),
    .I_reg_rb_sub_version(SUB_VERSION),
    .I_reg_rb_mini_version(MINI_VERSION),
    .I_reg_rb_date_year(DATE[31:24]),
    .I_reg_rb_date_month(DATE[23:16]),
    .I_reg_rb_date_day(DATE[15:8]),
    .I_reg_rb_date_clock(DATE[7:0]),
    .I_reg_rb_video_not_active(reg_rb_video_not_active),
    .I_reg_rb_vin_width(reg_rb_vin_width_to_pc),
    .I_reg_rb_vin_height(reg_rb_vin_height_to_pc),
    .I_reg_rb_vin_frame_rate(reg_rb_vin_frame_rate),
    .I_reg_rb_c1_calib_done(),
    .I_reg_rb_c3_calib_done(),
    .I_reg_rb_need_reboot_to_test(reg_rb_need_reboot_to_test),
    .I_reg_rb_ddr3_err(),
    .I_reg_p0_rb_comm_back_flag(reg_p0_rb_comm_back_flag),
    .I_reg_p0_rb_comm_back_crc_err(reg_p0_rb_comm_back_crc_err),
    .I_reg_p0_rb_comm_back_length(reg_p0_rb_comm_back_length),
    .I_reg_p0_rb_sending_comm_pkg(reg_p0_rb_sending_comm_pkg),
    .I_reg_p1_rb_comm_back_flag(reg_p1_rb_comm_back_flag),
    .I_reg_p1_rb_comm_back_crc_err(reg_p1_rb_comm_back_crc_err),
    .I_reg_p1_rb_comm_back_length(reg_p1_rb_comm_back_length),
    .I_reg_p1_rb_sending_comm_pkg(reg_p1_rb_sending_comm_pkg),
    .I_reg_p2_rb_comm_back_flag(),
    .I_reg_p2_rb_comm_back_crc_err(),
    .I_reg_p2_rb_comm_back_length(),
    .I_reg_p2_rb_sending_comm_pkg(),
    .I_reg_p3_rb_comm_back_flag(),
    .I_reg_p3_rb_comm_back_crc_err(),
    .I_reg_p3_rb_comm_back_length(),
    .I_reg_p3_rb_sending_comm_pkg(),
    .O_reg_reboot_addr(reg_reboot_addr),
    .O_reg_reboot_en(reg_reboot_en),
    .O_sc_reg_reset_ddr3(reg_reset_ddr3),
    .O_reg_vib_enable(reg_vib_enable),
    .O_reg_px_enable(reg_px_enable),
    .O_sc_reg_px_send_comm_pkg(reg_px_send_comm_pkg),
    .O_sc_reg_p0_send_comm_pkg(reg_p0_send_comm_pkg),
    .O_sc_reg_p0_clr_comm_back_flag(reg_p0_clr_comm_back_flag),
    .O_sc_reg_p1_send_comm_pkg(reg_p1_send_comm_pkg),
    .O_sc_reg_p1_clr_comm_back_flag(reg_p1_clr_comm_back_flag),
    .O_sc_reg_p2_send_comm_pkg(),
    .O_sc_reg_p2_clr_comm_back_flag(),
    .O_sc_reg_p3_send_comm_pkg(),
    .O_sc_reg_p3_clr_comm_back_flag(),
    .O_reg_nop_bytes(reg_nop_bytes),
    .O_reg_frame_pkg_byte_num(reg_frame_pkg_byte_num),
    .O_reg_disp_set_pkg_byte_num(reg_disp_set_pkg_byte_num),
    .O_reg_idle_pkg_byte_num(reg_idle_pkg_byte_num),
    .O_reg_comm_pkg_byte_num(reg_comm_pkg_byte_num),
    .O_reg_mac_addr_incr_en(reg_mac_addr_incr_en),
    .O_reg_max_pixel_num_in_one_trans(reg_max_pixel_num_in_one_trans),
    .O_reg_long_pkg_en(reg_long_pkg_en),
    .O_reg_px_start_row_offset(reg_px_start_row_offset),
    .O_reg_px_start_col_offset(reg_px_start_col_offset),
    .O_reg_vin_max_width(reg_vin_max_width),
    .O_reg_vin_max_height(reg_vin_max_height),
    .O_reg_p0_enable(reg_p0_enable),
    .O_reg_p0_start_row(reg_p0_start_row),
    .O_reg_p0_start_col(reg_p0_start_col),
    .O_reg_p0_width(reg_p0_width),
    .O_reg_p0_height(reg_p0_height),
    .O_reg_p0_disable_disp_set_pkg(reg_p0_disable_disp_set_pkg),
    .O_reg_p0_hori_invert_en(),
    .O_reg_p0_vert_invert_en(),
    .O_reg_p0_audio_enable(reg_p0_audio_enable),
    .O_reg_p0_line_step(reg_p0_line_step),
    .O_reg_p1_enable(reg_p1_enable),
    .O_reg_p1_start_row(reg_p1_start_row),
    .O_reg_p1_start_col(reg_p1_start_col),
    .O_reg_p1_width(reg_p1_width),
    .O_reg_p1_height(reg_p1_height),
    .O_reg_p1_disable_disp_set_pkg(reg_p1_disable_disp_set_pkg),
    .O_reg_p1_hori_invert_en(),
    .O_reg_p1_vert_invert_en(),
    .O_reg_p1_audio_enable(reg_p1_audio_enable),
    .O_reg_p1_line_step(reg_p1_line_step),
    .O_reg_p2_enable(),
    .O_reg_p2_start_row(),
    .O_reg_p2_start_col(),
    .O_reg_p2_width(),
    .O_reg_p2_height(),
    .O_reg_p2_disable_disp_set_pkg(),
    .O_reg_p2_hori_invert_en(),
    .O_reg_p2_vert_invert_en(),
    .O_reg_p2_audio_enable(),
    .O_reg_p2_line_step(),
    .O_reg_p3_enable(),
    .O_reg_p3_start_row(),
    .O_reg_p3_start_col(),
    .O_reg_p3_width(),
    .O_reg_p3_height(),
    .O_reg_p3_disable_disp_set_pkg(),
    .O_reg_p3_hori_invert_en(),
    .O_reg_p3_vert_invert_en(),
    .O_reg_p3_audio_enable(),
    .O_reg_p3_line_step(),
    .O_reg_upscale_width(reg_upscale_width),
    .O_reg_is_sv5(reg_is_sv5),
    .O_reg_screen_v(reg_screen_v),
    .O_reg_vin_mode(reg_vin_mode),
    .O_reg_Android_state(reg_Android_state),
    .I_reg_Android_system_ok(Android_system_ok)

);

//--------------------------------------------------------------------
// clk
//--------------------------------------------------------------------
sys_pll u_sys_pll(
    .areset(!init_pll),
    .inclk0(I_osc_25M),
    .c0(sclk),
    .c1()
);

assign init_pll = reset_init[5];

always @(posedge I_osc_25M)
    if (!init_pll)
        reset_init <= reset_init + 1'b1;

//--------------------------------------------------------------------
// rst_n
//--------------------------------------------------------------------
sys_reset_ctrl sys_reset_ctrl(
    .sclkin(I_osc_25M),
    .resetb(rst_n)
);

//--------------------------------------------------------------------
// vib_top
//--------------------------------------------------------------------
assign vin_pclk = ~I_vin_pclk;

vib_top
#(
    .MAX_VIN_WIDTH(MAX_VIN_WIDTH),
    .FRAME1_START_ADDR(FRAME1_START_ADDR)
)
u_vib_top
(
    .I_sclk(sclk),
    .I_rst_n(rst_n/* && !reg_reset_ddr3*/),
    .I_vin_pclk(vin_pclk),
    .I_vin_vsync(I_vin_vsync),
    .I_vin_de(I_vin_de),
    .I_vin_data(I_vin_data),
    .O_vin_led(),
    .O_new_frame(new_frame),
    .O_vib_use_buf1(vib_use_buf1),
    .O_sdm1_vib_req(sdm1_vib_req),
    .I_sdm1_vib_ack(sdm1_vib_ack),
    .I_sdm1_sdram_wr_rd_end(sdm_sdram_wr_rd_end),
    .O_sdm1_sdram_wr_en(sdm1_sdram_wr_en),
    .O_sdm1_sdram_start_addr(sdm1_sdram_start_addr),
    .O_sdm1_sdram_length(sdm1_sdram_length),
    .I_sdm1_sdram_ask_for_data(sdm1_sdram_ask_for_data),
    .O_sdm1_sdram_wdata(sdm1_sdram_wdata),
    .O_sdm2_vib_req(sdm2_vib_req),
    .I_sdm2_vib_ack(sdm2_vib_ack),
    .I_sdm2_sdram_wr_rd_end(sdm_sdram_wr_rd_end),
    .O_sdm2_sdram_wr_en(sdm2_sdram_wr_en),
    .O_sdm2_sdram_start_addr(sdm2_sdram_start_addr),
    .O_sdm2_sdram_length(sdm2_sdram_length),
    .I_sdm2_sdram_ask_for_data(sdm2_sdram_ask_for_data),
    .O_sdm2_sdram_wdata(sdm2_sdram_wdata),
    .I_reg_vib_enable(reg_vib_enable),
    .O_reg_rb_vin_width(reg_rb_vin_width),
    .O_reg_rb_vin_height(reg_rb_vin_height),
    .O_reg_rb_vin_width_to_pc(reg_rb_vin_width_to_pc),
    .O_reg_rb_vin_height_to_pc(reg_rb_vin_height_to_pc),
    .O_reg_rb_vin_frame_rate(reg_rb_vin_frame_rate),
    .O_reg_rb_video_not_active(reg_rb_video_not_active),
    .O_reg_rb_ddr3_err(),
    .I_reg_px_start_row_offset(reg_px_start_row_offset),
    .I_reg_px_start_col_offset(reg_px_start_col_offset),
    .I_reg_vin_max_width(reg_vin_max_width),
    .I_reg_vin_max_height(reg_vin_max_height),
    .I_reg_vin_mode(reg_vin_mode)
);

//--------------------------------------------------------------------
// p0 output
//--------------------------------------------------------------------
net_top
#(
    .MAX_VIN_WIDTH(MAX_VIN_WIDTH),
    .FRAME1_START_ADDR(FRAME1_START_ADDR),
    .AUDIO_EN(1)
)
u_net_top_p0
(
    .I_sclk(sclk),
    .I_rst_n(rst_n/* && !reg_reset_ddr3*/),
    .I_new_frame(new_frame),
    .I_vib_use_buf1(vib_use_buf1),
    .I_video_not_active(reg_rb_video_not_active),
    .I_send_disp_set_pkg_start(send_disp_set_pkg_start),
    .O_rgmii_txc(rgmii_p0_txc),
    .O_rgmii_txen(rgmii_p0_txen),
    .O_rgmii_txd(rgmii_p0_txd),
    .I_rgmii_rxc(rgmii_p0_rxc),
    .I_rgmii_rxdv(rgmii_p0_rxdv),
    .I_rgmii_rxd(rgmii_p0_rxd),
    .O_px_rxc(p0_rxc),
    .O_px_rxdv(p0_rxdv),
    .O_px_rxer(p0_rxer),
    .O_sdm_vob_req(sdm_vob_req_p0),
    .I_sdm_vob_ack(sdm_vob_ack_p0),
    .I_sdm_sdram_wr_rd_end(sdm_sdram_wr_rd_end),
    .O_sdm_sdram_rd_en(sdm_sdram_rd_en_p0),
    .O_sdm_sdram_start_addr(sdm_sdram_start_addr_p0),
    .O_sdm_sdram_length(sdm_sdram_length_p0),
    .I_sdm_sdram_rdata(sdm_sdram_rdata),
    .I_sdm_sdram_rdata_valid(sdm_sdram_rdata_valid & sdm_vob_ack_p0),
    .I_reg_rb_vin_width(reg_rb_vin_width),
    .I_reg_px_enable(reg_p0_enable && reg_px_enable),
    .I_reg_nop_bytes(reg_nop_bytes),
    .I_reg_frame_pkg_byte_num(reg_frame_pkg_byte_num),
    .I_reg_disable_disp_set_pkg(reg_p0_disable_disp_set_pkg),
    .I_reg_disp_set_pkg_byte_num(reg_disp_set_pkg_byte_num),
    .I_reg_idle_pkg_byte_num(reg_idle_pkg_byte_num),
    .I_reg_send_comm_pkg(reg_p0_send_comm_pkg | reg_px_send_comm_pkg),
    .I_reg_comm_pkg_byte_num(reg_comm_pkg_byte_num),
    .I_reg_px_start_row(reg_p0_start_row),
    .I_reg_px_start_col(reg_p0_start_col),
    .I_reg_px_width(reg_p0_width),
    .I_reg_px_height(reg_p0_height),
    .I_reg_clr_comm_back_flag(reg_p0_clr_comm_back_flag),
    .O_reg_rb_comm_back_flag(reg_p0_rb_comm_back_flag),
    .O_reg_rb_comm_back_crc_err(reg_p0_rb_comm_back_crc_err),
    .O_reg_rb_comm_back_length(reg_p0_rb_comm_back_length),
    .O_reg_rb_sending_comm_pkg(reg_p0_rb_sending_comm_pkg),
    .I_reg_px_start_row_offset(12'd0/*reg_px_start_row_offset*/),
    .I_reg_px_start_col_offset(12'd0/*reg_px_start_col_offset*/),
    .I_reg_mac_addr_incr_en(1'b0/*reg_mac_addr_incr_en*/),
    .I_reg_max_pixel_num_in_one_trans(reg_max_pixel_num_in_one_trans),
    .I_reg_long_pkg_en(1'b0/*reg_long_pkg_en*/),
    .I_reg_px_line_step(reg_p0_line_step),
    .I_reg_px_hori_invert_en(1'b0),
    .I_reg_px_vert_invert_en(1'b0),
    .I_reg_px_audio_enable(reg_p0_audio_enable),
    .I_pkg_ram_wen(px_pkg_ram_wren[0]),
    .I_pkg_ram_waddr(waddr),
    .I_pkg_ram_wdata(wdata),
    .I_pkg_ram_rden(px_pkg_ram_rden[0]),
    .I_pkg_ram_raddr(raddr),
    .O_pkg_ram_rdata(p0_pkg_ram_rdata),
    .I_comm_back_ram_ren(px_comm_back_ram_rden[0]),
    .I_comm_back_ram_raddr(raddr[10:0]),
    .O_comm_back_ram_rdata(p0_comm_back_ram_rdata),
    .I_audio_data_valid(audio_data_valid),
    .I_audio_data(audio_data),
    .O_reg_reboot_to_test(reboot_to_test_p0)
);

//--------------------------------------------------------------------
// p1 output
//--------------------------------------------------------------------
net_top
#(
    .MAX_VIN_WIDTH(MAX_VIN_WIDTH),
    .FRAME1_START_ADDR(FRAME1_START_ADDR),
    .AUDIO_EN(1)
)
u_net_top_p1
(
    .I_sclk(sclk),
    .I_rst_n(rst_n/* && !reg_reset_ddr3*/),
    .I_new_frame(new_frame),
    .I_vib_use_buf1(vib_use_buf1),
    .I_video_not_active(reg_rb_video_not_active),
    .I_send_disp_set_pkg_start(send_disp_set_pkg_start),
    .O_rgmii_txc(rgmii_p1_txc),
    .O_rgmii_txen(rgmii_p1_txen),
    .O_rgmii_txd(rgmii_p1_txd),
    .I_rgmii_rxc(rgmii_p1_rxc),
    .I_rgmii_rxdv(rgmii_p1_rxdv),
    .I_rgmii_rxd(rgmii_p1_rxd),
    .O_px_rxc(p1_rxc),
    .O_px_rxdv(p1_rxdv),
    .O_px_rxer(p1_rxer),
    .O_sdm_vob_req(sdm_vob_req_p1),
    .I_sdm_vob_ack(sdm_vob_ack_p1),
    .I_sdm_sdram_wr_rd_end(sdm_sdram_wr_rd_end),
    .O_sdm_sdram_rd_en(sdm_sdram_rd_en_p1),
    .O_sdm_sdram_start_addr(sdm_sdram_start_addr_p1),
    .O_sdm_sdram_length(sdm_sdram_length_p1),
    .I_sdm_sdram_rdata(sdm_sdram_rdata),
    .I_sdm_sdram_rdata_valid(sdm_sdram_rdata_valid & sdm_vob_ack_p1),
    .I_reg_rb_vin_width(reg_rb_vin_width),
    .I_reg_px_enable(reg_p1_enable && reg_px_enable),
    .I_reg_nop_bytes(reg_nop_bytes),
    .I_reg_frame_pkg_byte_num(reg_frame_pkg_byte_num),
    .I_reg_disable_disp_set_pkg(reg_p1_disable_disp_set_pkg),
    .I_reg_disp_set_pkg_byte_num(reg_disp_set_pkg_byte_num),
    .I_reg_idle_pkg_byte_num(reg_idle_pkg_byte_num),
    .I_reg_send_comm_pkg(reg_p1_send_comm_pkg | reg_px_send_comm_pkg),
    .I_reg_comm_pkg_byte_num(reg_comm_pkg_byte_num),
    .I_reg_px_start_row(reg_p1_start_row),
    .I_reg_px_start_col(reg_p1_start_col),
    .I_reg_px_width(reg_p1_width),
    .I_reg_px_height(reg_p1_height),
    .I_reg_clr_comm_back_flag(reg_p1_clr_comm_back_flag),
    .O_reg_rb_comm_back_flag(reg_p1_rb_comm_back_flag),
    .O_reg_rb_comm_back_crc_err(reg_p1_rb_comm_back_crc_err),
    .O_reg_rb_comm_back_length(reg_p1_rb_comm_back_length),
    .O_reg_rb_sending_comm_pkg(reg_p1_rb_sending_comm_pkg),
    .I_reg_px_start_row_offset(12'd0/*reg_px_start_row_offset*/),
    .I_reg_px_start_col_offset(12'd0/*reg_px_start_col_offset*/),
    .I_reg_mac_addr_incr_en(1'b0/*reg_mac_addr_incr_en*/),
    .I_reg_max_pixel_num_in_one_trans(reg_max_pixel_num_in_one_trans),
    .I_reg_long_pkg_en(1'b0/*reg_long_pkg_en*/),
    .I_reg_px_line_step(reg_p1_line_step),
    .I_reg_px_hori_invert_en(1'b0),
    .I_reg_px_vert_invert_en(1'b0),
    .I_reg_px_audio_enable(1'b0/*reg_p1_audio_enable*/),
    .I_pkg_ram_wen(px_pkg_ram_wren[1]),
    .I_pkg_ram_waddr(waddr),
    .I_pkg_ram_wdata(wdata),
    .I_pkg_ram_rden(px_pkg_ram_rden[1]),
    .I_pkg_ram_raddr(raddr),
    .O_pkg_ram_rdata(p1_pkg_ram_rdata),
    .I_comm_back_ram_ren(px_comm_back_ram_rden[1]),
    .I_comm_back_ram_raddr(raddr[10:0]),
    .O_comm_back_ram_rdata(p1_comm_back_ram_rdata),
    .I_audio_data_valid(audio_data_valid),
    .I_audio_data(audio_data),
    .O_reg_reboot_to_test(reboot_to_test_p1)
);

//--------------------------------------------------------------------
// state machine : sdm_arbi_state
//--------------------------------------------------------------------
always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm_arbi_state <= SDM_ARBI_IDLE;
    else
        sdm_arbi_state <= next_sdm_arbi_state;

always @(*)
    case (sdm_arbi_state)
        SDM_ARBI_IDLE:
            if (sdm1_vib_req)
                next_sdm_arbi_state = SDM_ARBI_VIB_1;
            else if (sdm2_vib_req)
                next_sdm_arbi_state = SDM_ARBI_VIB_2;
            else if (sdm_vob_req_p0)
                next_sdm_arbi_state = SDM_ARBI_P0;
            else if (sdm_vob_req_p1)
                next_sdm_arbi_state = SDM_ARBI_P1;
            else if (sdm_vob_req_p2)
                next_sdm_arbi_state = SDM_ARBI_P2;
            else if (sdm_vob_req_p3)
                next_sdm_arbi_state = SDM_ARBI_P3;
            else
                next_sdm_arbi_state = SDM_ARBI_IDLE;
        SDM_ARBI_VIB_1:
            if (!sdm1_vib_req)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_VIB_1;
        SDM_ARBI_VIB_2:
            if (!sdm2_vib_req)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_VIB_2;
        SDM_ARBI_P0:
            if (!sdm_vob_req_p0)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_P0;
        SDM_ARBI_P1:
            if (!sdm_vob_req_p1)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_P1;
        SDM_ARBI_P2:
            if (!sdm_vob_req_p2)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_P2;
        SDM_ARBI_P3:
            if (!sdm_vob_req_p3)
                next_sdm_arbi_state = SDM_ARBI_IDLE;
            else
                next_sdm_arbi_state = SDM_ARBI_P3;
        default:
            next_sdm_arbi_state = SDM_ARBI_IDLE;
    endcase

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm1_vib_ack <= 1'b0;
    else
        sdm1_vib_ack <= sdm_arbi_state == SDM_ARBI_VIB_1;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm2_vib_ack <= 1'b0;
    else
        sdm2_vib_ack <= sdm_arbi_state == SDM_ARBI_VIB_2;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm_vob_ack_p0 <= 1'b0;
    else
        sdm_vob_ack_p0 <= sdm_arbi_state == SDM_ARBI_P0;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm_vob_ack_p1 <= 1'b0;
    else
        sdm_vob_ack_p1 <= sdm_arbi_state == SDM_ARBI_P1;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm_vob_ack_p2 <= 1'b0;
    else
        sdm_vob_ack_p2 <= sdm_arbi_state == SDM_ARBI_P2;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        sdm_vob_ack_p3 <= 1'b0;
    else
        sdm_vob_ack_p3 <= sdm_arbi_state == SDM_ARBI_P3;

assign sdm_sdram_start_addr = sdm1_vib_ack ? sdm1_sdram_start_addr : (sdm2_vib_ack ? sdm2_sdram_start_addr : (sdm_vob_ack_p0 ? sdm_sdram_start_addr_p0 : 
                                                                                                              (sdm_vob_ack_p1 ? sdm_sdram_start_addr_p1 : 
                                                                                                              (sdm_vob_ack_p2 ? sdm_sdram_start_addr_p2 : 
                                                                                                              (sdm_vob_ack_p3 ? sdm_sdram_start_addr_p3 : 
                                                                                                              'd0)))));
assign sdm_sdram_length = sdm1_vib_ack ? sdm1_sdram_length : (sdm2_vib_ack ? sdm2_sdram_length : (sdm_vob_ack_p0 ? sdm_sdram_length_p0 : 
                                                                                                 (sdm_vob_ack_p1 ? sdm_sdram_length_p1 : 
                                                                                                 (sdm_vob_ack_p2 ? sdm_sdram_length_p2 : 
                                                                                                 (sdm_vob_ack_p3 ? sdm_sdram_length_p3 :
                                                                                                 'd0)))));

// vob
assign sdm_sdram_rd_en = sdm_vob_ack_p0 ? sdm_sdram_rd_en_p0 : (sdm_vob_ack_p1 ? sdm_sdram_rd_en_p1 : (sdm_vob_ack_p2 ? sdm_sdram_rd_en_p2 : (sdm_vob_ack_p3 ? sdm_sdram_rd_en_p3 : 1'b0)));
assign sdm_sdram_wr_en = sdm1_vib_ack ? sdm1_sdram_wr_en : sdm2_vib_ack ? sdm2_sdram_wr_en : 1'b0;

// vib
assign sdm1_sdram_ask_for_data = sdm1_vib_ack && sdm_sdram_ask_for_data;
assign sdm2_sdram_ask_for_data = sdm2_vib_ack && sdm_sdram_ask_for_data;
assign sdm_sdram_wdata = sdm1_vib_ack ? sdm1_sdram_wdata : sdm2_sdram_wdata;

//--------------------------------------------------------------------
// SDRAM
//--------------------------------------------------------------------
sdram_ctl #(
    .ROW_WTH(11),
    .COL_WTH(8),
    .BANK_WTH(2),
    .DATA_WTH(32)
) u_sdram_ctl_2 (
    //system signals
    .sclk(sclk),
    .sclk_shift(sclk),
    .rst_n(rst_n),
    //interface with internal logic
    .sdram_initializing(),
    .wr_en(sdm_sdram_wr_en),
    .rd_en(sdm_sdram_rd_en),
    .wr_rd_end(sdm_sdram_wr_rd_end),
    .start_addr(sdm_sdram_start_addr),
    .length(sdm_sdram_length),
    .ask_for_data(sdm_sdram_ask_for_data),
    .data_in(sdm_sdram_wdata),
    .data_out(sdm_sdram_rdata),
    .data_out_valid(sdm_sdram_rdata_valid),
    // interface with SDRAM
    .sdram_cke(sdm_cke),
    .sdram_cs_n(sdm_cs),
    .sdram_ras_n(sdm_ras),
    .sdram_cas_n(sdm_cas),
    .sdram_we_n(sdm_we),
    .sdram_clk(sdm_clk),
    .sdram_bank(sdm_bank),
    .sdram_addr(sdm_addr),
    .sdram_dqm(/*sdm2_dqm*/),
    .sdram_data(sdm_data)
);

assign sdm_dqm = 'd0;

//--------------------------------------------------------------------
// AR8035
//--------------------------------------------------------------------
AR8035_top u_AR8035_top(
    .sclk(I_osc_25M), 
    .rst_n(phy_rst_n),   
    .mdc(mdc),
    .mdio(mdio)
);

// phy check
always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        ms_cnt <= 17'd124999;
    else if (ms_tick)
        ms_cnt <= 17'd124999;
    else
        ms_cnt <= ms_cnt - 1'b1;
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        ms_tick <= 1'b0;
    else if (ms_cnt == 1'b1)
        ms_tick <= 1'b1;
    else
        ms_tick <= 1'b0;
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        start_state <= START_IDLE;
    else if (reset_phy_sync[3:2] == 2'b01)
        start_state <= START_IDLE;
    else
        start_state <= next_start_state;
end

always @(*) begin
    case (start_state)
        START_IDLE:
            next_start_state = START_DELAY;
        START_DELAY:
            if (delay_cnt >= 8'd100)
                next_start_state = START_OK;
            else
                next_start_state = START_DELAY;
        START_OK:
            next_start_state = START_OK;
        default:
            next_start_state = START_IDLE;
    endcase
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        delay_cnt <= 1'b0;
    else if (start_state == START_IDLE)
        delay_cnt <= 1'b0;
    else
        delay_cnt <= delay_cnt  + 1'b1;
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        phy_rst_n <= 1'b0;
    else if (start_state == START_OK)
        phy_rst_n <= 1'b1;
    else
        phy_rst_n <= 1'b0;
end

assign phy0_rst_n = phy_rst_n;
assign phy1_rst_n = phy_rst_n;

always @(posedge sclk) begin
    reset_phy_sync <= {reset_phy_sync[2:0], (p0_error | p1_error )};
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        check_phy <= 1'b0;
    else if (reset_phy_sync[3:2] == 2'b01)
        check_phy <= 1'b0;
    else if (check_phy_timer == 1'b0)
        check_phy <= 1'b1;
end

always @(posedge sclk or negedge rst_n) begin
    if (!rst_n)
        check_phy_timer <= 14'd10000; // 启动前10秒不监测phy
    else if (reset_phy_sync[3:2] == 2'b01)
        check_phy_timer <= 14'd10000; // 复位phy10秒内不监测phy
    else if (ms_tick && check_phy_timer != 1'b0)
        check_phy_timer <= check_phy_timer - 1'b1;
end

// px_check
px_check p0_check (
    .I_sclk    ( sclk ),
    .I_rst_n   ( check_phy ),
    .I_ms_tick ( ms_tick ),
    .I_rxc     ( p0_rxc ),
    .I_rxdv    ( p0_rxdv ),
    .I_rxer    ( p0_rxer ),
    .O_error   ( p0_error ),
    .O_in_1000M( p0_in_1000M )
);

// px_check
px_check p1_check (
    .I_sclk    ( sclk ),
    .I_rst_n   ( check_phy ),
    .I_ms_tick ( ms_tick ),
    .I_rxc     ( p1_rxc ),
    .I_rxdv    ( p1_rxdv ),
    .I_rxer    ( p1_rxer ),
    .O_error   ( p1_error ),
    .O_in_1000M( p1_in_1000M )
);

//--------------------------------------------------------------------
// audio_input
//--------------------------------------------------------------------
//audio_input u_audio_input
//(
//    .I_sclk(sclk),
//    .I_clk_25m(I_osc_25M),
//    .mclk(mclk),
//    .lrck(lrck),
//    .sck(sck),
//    .sda(sda),
//    .O_audio_data(audio_data),
//    .O_audio_data_valid(audio_data_valid)
//);

//--------------------------------------------------------------------
// LED
//--------------------------------------------------------------------
reg  [ 6: 0] time0;
reg  [ 9: 0] time1;
reg  [ 8: 0] time2;

always @(posedge sclk)
    time0 <= time0 + 1'b1;

always @(posedge sclk)
    if (time1 == 1023)
        time1 <= 'd0;
    else if (time0 == 127)
        begin
        time1 <= time1 + 1'b1;
        end

always @(posedge sclk)
    if (time1 == 1023)
        time2 <= time2 + 1'b1;

always @(posedge sclk)
    if (send_disp_set_pkg_start)
        send_disp_set_pkg_start <= 1'b0;
    else if (reg_rb_video_not_active && time1 == 1023)
        send_disp_set_pkg_start <= 1'b1;
        
// assign p0_led = p0_in_1000M ? 1'b0 : 1'b1;
// assign p1_led = p1_in_1000M ? 1'b0 : 1'b1;

//--------------------------------------------------------------------
// LED
//--------------------------------------------------------------------
reg	[31:0]	time_count;
reg	[4:0]	flag;
reg			Android_system_ok;
reg			state;

always @(posedge sclk or negedge rst_n)
begin
    if(!rst_n)
        Android_system_ok <= 'd0;
    else if(state == 1'b0)
		Android_system_ok <= reg_Android_state != 'd0;
	else 
		Android_system_ok <= 'd0;
end

always @(posedge sclk or negedge rst_n)
begin
    if(!rst_n)
        time_count <= 'd0;
    else if(time_count == 'd124999999)
        time_count <= 'd0;
	else
        time_count <= time_count + 'd1;
end

always @(posedge sclk or negedge rst_n)
begin
    if(!rst_n)
        flag <= 'd0;
    else if(time_count == 'd124999999)
	begin
		if(flag == 'd18)
			flag <= 'd3;
		else
			flag <= flag + 'd1;
	end
	else
        flag <= flag;
end


always @(posedge sclk or negedge rst_n)
begin
    if(!rst_n)
        state  <= 'd0;
	else
	begin
		case(state)
			1'b0:
			begin
				if(flag < 'd3)
					state  <= 'd0;
				else if(Android_system_ok)
					state  <= 'd1;
				else
					state  <= 'd0;
			end
			
			1'b1:
			begin
				if(flag == 'd18 && time_count == 'd124999999)
					state  <= 'd0;
				else
					state  <= 'd1;
			end
		endcase
	end
end


always @(posedge sclk or negedge rst_n)
begin
    if(!rst_n)
        O_led0 <= 'd0;
	else
	begin
		if(state == 1'b0)
		begin
			if(flag < 4'd3)
			begin
				if(time_count < 'd31250000)
					O_led0 <= 'd1;
				else if(time_count < 'd62500000)
					O_led0 <= 'd0;
				else if(time_count < 'd93750000)
					O_led0 <= 'd1;
				else
					O_led0 <= 'd0;
			end
			else
			begin
				if(Android_system_ok)
					O_led0 <= O_led0;
				else
					O_led0 <= 1'b1;
			end
		end
		else
		begin
			if(time_count == 'd124999999)
				O_led0 <= !O_led0;
			else
				O_led0 <= O_led0;
		end
	end
end	
	

//--------------------------------------------------------------------
// reboot
//--------------------------------------------------------------------
wire reboot_o_osc;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        reboot_to_test <= 1'b0;
    else
        reboot_to_test <= reboot_to_test_p0 | reboot_to_test_p1;

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        reboot_to_test_cnt <= 'd0;
    else if (new_frame)
        reboot_to_test_cnt <= 'd0;
    else if (reboot_to_test)
        begin
        if (!reboot_to_test_cnt[2])
            reboot_to_test_cnt <= reboot_to_test_cnt + 1'b1;
        end

always @(posedge sclk or negedge rst_n)
    if (!rst_n)
        reg_rb_need_reboot_to_test <= 1'b0;
    else
        reg_rb_need_reboot_to_test <= reboot_to_test_cnt[2];

alta_boot reboot(
    .i_boot(reg_rb_need_reboot_to_test),
    .im_vector_sel('d1),
    .i_osc_enb(1'b1),
    .o_osc(reboot_o_osc)
);


endmodule
`default_nettype wire

